﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MessageWorkflow.Graph.Algorithm
{
    /// <summary>
    /// Triggers an action on each value making sure that all the dependents of that value are triggered first
    /// </summary>
    class OderlyNodeVisitor<T>
    {
        protected IGraph<T> Graph { get; private set; }

        protected ICollection<T> VisitedNodes { get; private set; }

        public OderlyNodeVisitor(IGraph<T> graph)
        {
            if (graph == null)
            {
                throw new ArgumentNullException("graph");
            }

            Graph = graph;
        }

        public IEnumerable<T> Visit()
        {
#if WINDOWS_PHONE
            VisitedNodes = new List<T>();
#else
            // default
            VisitedNodes = new HashSet<T>();
#endif

            return from node in Graph.Nodes
                   from subNode in VisitOrderly(node)
                   select subNode;
        }

        private IEnumerable<T> VisitOrderly(T node)
        {
            if (!VisitedNodes.Contains(node))
            {
                VisitedNodes.Add(node);

                // handle parents first
                var predeccessors = from predecessor in Graph.GetPredecessors(node)
                                    from orderlyPredecessor in VisitOrderly(predecessor)
                                    select orderlyPredecessor;

                foreach (var predecessor in predeccessors)
                {
                    yield return predecessor;
                }

                // finally handle current value
                yield return node;
            }
        }
    }
}
